
//此源码被清华学神尹成大魔王专业翻译分析并修改
//尹成QQ77025077
//尹成微信18510341407
//尹成所在QQ群721929980
//尹成邮箱 yinc13@mails.tsinghua.edu.cn
//尹成毕业于清华大学,微软区块链领域全球最有价值专家
//https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
/*
 *@文件api_tests.cpp
 *@eos/license中定义的版权
 **/

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
#include <boost/test/unit_test.hpp>
#pragma GCC diagnostic pop

#include <eosio/testing/tester.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/resource_limits.hpp>

#include <fc/exception/exception.hpp>
#include <fc/variant_object.hpp>

#include "eosio_system_tester.hpp"

#include <test_ram_limit/test_ram_limit.abi.hpp>
#include <test_ram_limit/test_ram_limit.wast.hpp>

/*
 *注册测试套件“RAM测试”
 **/

BOOST_AUTO_TEST_SUITE(ram_tests)



/*************************************************************************
 *RAM测试用例
 *************************************************************************/

BOOST_FIXTURE_TEST_CASE(ram_tests, eosio_system::eosio_system_tester) { try {
   auto init_request_bytes = 80000;
   const auto increment_contract_bytes = 10000;
   const auto table_allocation_bytes = 12000;
   BOOST_REQUIRE_MESSAGE(table_allocation_bytes > increment_contract_bytes, "increment_contract_bytes must be less than table_allocation_bytes for this test setup to work");
   buyrambytes(config::system_account_name, config::system_account_name, 70000);
   produce_blocks(10);
   create_account_with_resources(N(testram11111),config::system_account_name, init_request_bytes + 40);
   create_account_with_resources(N(testram22222),config::system_account_name, init_request_bytes + 1190);
   produce_blocks(10);
   BOOST_REQUIRE_EQUAL( success(), stake( "eosio.stake", "testram11111", core_from_string("10.0000"), core_from_string("5.0000") ) );
   produce_blocks(10);

   for (auto i = 0; i < 10; ++i) {
      try {
         set_code( N(testram11111), test_ram_limit_wast );
         break;
      } catch (const ram_usage_exceeded&) {
         init_request_bytes += increment_contract_bytes;
         buyrambytes(config::system_account_name, N(testram11111), increment_contract_bytes);
         buyrambytes(config::system_account_name, N(testram22222), increment_contract_bytes);
      }
   }
   produce_blocks(10);

   for (auto i = 0; i < 10; ++i) {
      try {
         set_abi( N(testram11111), test_ram_limit_abi );
         break;
      } catch (const ram_usage_exceeded&) {
         init_request_bytes += increment_contract_bytes;
         buyrambytes(config::system_account_name, N(testram11111), increment_contract_bytes);
         buyrambytes(config::system_account_name, N(testram22222), increment_contract_bytes);
      }
   }
   produce_blocks(10);
   set_code( N(testram22222), test_ram_limit_wast );
   set_abi( N(testram22222), test_ram_limit_abi );
   produce_blocks(10);

   auto total = get_total_stake( N(testram11111) );
   const auto init_bytes =  total["ram_bytes"].as_uint64();

   auto rlm = control->get_resource_limits_manager();
   auto initial_ram_usage = rlm.get_account_ram_usage(N(testram11111));

//计算我们需要为数据库存储再多分配多少字节
   auto more_ram = table_allocation_bytes + init_bytes - init_request_bytes;
   BOOST_REQUIRE_MESSAGE(more_ram >= 0, "Underlying understanding changed, need to reduce size of init_request_bytes");
   wdump((init_bytes)(initial_ram_usage)(init_request_bytes)(more_ram) );
   buyrambytes(config::system_account_name, N(testram11111), more_ram);
   buyrambytes(config::system_account_name, N(testram22222), more_ram);

   TESTER* tester = this;
//仅在分配的字节下分配
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 1)
                        ("to", 10)
                        /*尺寸“，1780/*1910*/）；
   生产砌块（1）；
   auto-ram_usage=rlm.get_account_ram_usage（n（testram111111））；

   total=获取_total_股份（n（testram111111））；
   const auto ram_bytes=total[“ram_bytes”]。as_uint64（）；
   wdump（（ram_bytes）（ram_用法）（初始_ram_用法）（init_bytes）（ram_用法-初始_ram_用法）（init_bytes-ram_用法））；

   wlog（“RAM_测试1%
   //分配超出分配的字节数
   boost_需要_异常（
      测试仪->推送动作（n（testram111111），n（setentry），n（testram111111），mvo（）
                           （“付款人”，“测试计划11111”）
                           （“来自”，1）
                           （“to”，10）
                           （“尺寸”，1790/*192*/)),

                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   wlog("ram_tests 2    %%%%%%");
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(ram_usage, rlm.get_account_ram_usage(N(testram11111)));

//使用较小的分配更新条目，以便我们可以验证是否释放了空间并可以进行新的分配。
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 1)
                        ("to", 10)
                        /*尺寸“，1680/*1810*/）；
   生产砌块（1）；
   boost_需要_equal（RAM_usage-1000，rlm.get_account_RAM_usage（n（testram111111））；

   //验证添加的条目是否超出分配字节限制
   boost_需要_异常（
      测试仪->推送动作（n（testram111111），n（setentry），n（testram111111），mvo（）
                           （“付款人”，“测试计划11111”）
                           （“来自”，1）
                           （“to”，11）
                           （“尺寸”，1680/*181*/)),

                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(ram_usage - 1000, rlm.get_account_ram_usage(N(testram11111)));

//验证新条目的字节数减去现有条目的释放字节数是否仍超出分配字节数限制
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 1)
                           ("to", 11)
                           ("size", 1760)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(ram_usage - 1000, rlm.get_account_ram_usage(N(testram11111)));

//验证新条目的字节减去现有条目的释放字节是否在分配字节限制下
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 1)
                        ("to", 11)
                        /*尺寸“，1600/*1720*/）；
   生产砌块（1）；

   测试仪->推送动作（n（testram111111）、n（rmentry）、n（testram111111）、mvo（）
                        （“来自”，3）
                        （“to”，3）；
   生产砌块（1）；
   
   //验证新条目是否将超过分配字节限制
   boost_需要_异常（
      测试仪->推送动作（n（testram111111），n（setentry），n（testram111111），mvo（）
                           （“付款人”，“测试计划11111”）
                           （“来自”，12）
                           （“to”，12）
                           （尺寸，1780）），
                           超过RAM使用率，
                           fc_exception_message_starts_with（“account testram111111 has insufficient ram”））；
   生产砌块（1）；

   //验证新条目是否在分配字节限制下
   测试仪->推送动作（n（testram111111），n（setentry），n（testram111111），mvo（）
                        （“付款人”，“测试计划11111”）
                        （“来自”，12）
                        （“to”，12）
                        （“尺寸”，1620/*172*/));

   produce_blocks(1);

//验证新条目是否将超过分配字节限制，以设置新付款人的测试
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 13)
                           ("to", 13)
                           ("size", 1660)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);

//验证新条目是否在分配字节限制下
   tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                        ("payer", "testram22222")
                        ("from", 12)
                        ("to", 12)
                        ("size", 1720));
   produce_blocks(1);

//验证另一个太大的新条目是否会超过分配字节限制，以设置新付款人的测试。
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 13)
                           ("to", 13)
                           ("size", 1900)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);

   wlog("ram_tests 18    %%%%%%");
//验证新条目是否在分配字节限制下，因为条目12现在充电到testram2222
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 13)
                        ("to", 13)
                        ("size", 1720));
   produce_blocks(1);

//验证testram2222的新条目是否超出分配字节限制
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                           ("payer", "testram22222")
                           ("from", 12)
                           ("to", 21)
                           ("size", 1930)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram22222 has insufficient ram"));
   produce_blocks(1);

//验证testram2222的新条目是否在分配字节限制下
   tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                        ("payer", "testram22222")
                        ("from", 12)
                        ("to", 21)
                        ("size", 1910));
   produce_blocks(1);

//验证testram2222的新条目是否超出分配字节限制
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                           ("payer", "testram22222")
                           ("from", 22)
                           ("to", 22)
                           ("size", 1910)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram22222 has insufficient ram"));
   produce_blocks(1);

   tester->push_action( N(testram11111), N(rmentry), N(testram11111), mvo()
                        ("from", 20)
                        ("to", 20));
   produce_blocks(1);

//验证testram2222的新条目是否在分配字节限制下
   tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                        ("payer", "testram22222")
                        ("from", 22)
                        ("to", 22)
                        ("size", 1910));
   produce_blocks(1);

} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_SUITE_END()
